#include "COBJModel.h"

COBJModel::COBJModel ()
{
	Init ();
}

COBJModel::~COBJModel ()
{
}

void COBJModel::Init ()
{
	m_order[0] = '\0';
	m_iErrorCode = OBJERR_NONE;
}

bool COBJModel::LoadModel (const char* szFileName)
{
	String currentMaterial;// add by doki
	fstream	file;
	char	buf[BUF_LEN];
	Vector3	v, vn;
	Vector2 vt;
	Vector3 max, min;
	char	c = ' ';
	int		i, order = 0;

	m_v.clear ();
	m_vn.clear ();
	m_vt.clear ();
	m_f.clear ();

	Init ();

	max = Vector3::NEG_MAX;
	min = Vector3::POS_MAX;

	file.open (szFileName.c_str(), ios::in);
	if (!file)
	{
		m_iErrorCode = OBJERR_OPEN;
		return false;
	}

	currentMaterial.assign (L"not_set");

	while (!file.eof ())
	{
		file.get (buf[0]);

		switch (buf[0])
		{
		case ' ':
		case '#':
		case 'm':
		case 'g':
		case 'o':
		case 's':
			file.ignore (BUF_LEN, '\n');
			break;
		case 'u': // usemtl
			file.getline( &buf[1], 64);
			if( string( buf) >= "usemtl")
			{
				currentMaterial.assign( Ansi2WChar(&buf[7], static_cast<int>(strlen(buf)) - 6));
			}
			break;
		case 'v':
		case 'V':
			file.get (buf[1]);
			switch (buf[1])
			{
			case ' ':
				if (c != 'v')
				{
					for (i = 0; i < order; i++)
						if (m_order[i] == 'v')
						{
							c = 'v';
							break;
						}

					if (c != 'v')
					{
						m_order[order] = c = 'v';
						m_order[++order] = '\0';
					}
				}

				file >> v[0] >> v[1] >> v[2];
				m_v.push_back (v);

				for (i = 0; i < 3; i++)
				{
					if(v.val[i] > max.val[i])
						max.val[i] = v.val[i];
					if(v.val[i] < min.val[i])
						min.val[i] = v.val[i];
				}
				break;
			case 'n':
			case 'N':
				if (c != 'n')
				{
					for (i = 0; i < order; i++)
						if (m_order[i] == 'n')
						{
							c = 'n';
							break;
						}
					
					if (c != 'n')
					{
						m_order[order] = c = 'n';
						m_order[++order] = '\0';
					}
				}

				file >> vn.x >> vn.y >> vn.z;
				m_vn.push_back (vn);
				break;
			case 't':
			case 'T':
				if (c != 't')
				{
					for (i = 0; i < order; i++)
						if (m_order[i] == 't')
						{
							c = 't';
							break;
						}

					if (c != 't')
					{
						m_order[order] = c = 't';
						m_order[++order] = '\0';
					}
				}

				file >> vt.x >> vt.y;
				m_vt.push_back (vt);
				break;
			default:
				m_iErrorCode = OBJERR_STRUCT;
			}
			break;
		case 'f':
		case 'F':
			file.getline (buf, BUF_LEN, '\n');
			ReadFaces (currentMaterial, buf);
			break;
		case '\n':
			break;
		default:
			m_iErrorCode = OBJERR_STRUCT;
		}

		if (m_iErrorCode != OBJERR_NONE)
			return false;
	}

	mBBox.setPos ((max + min) / 2.0);
	//mBBox.setSize (max - min);

	return true;
}

void COBJModel::ReadFaces (const wstring& mat, char *buf)
{
	TCHAR		tmp[8];
	int			len;
	int			i, j, k;//, v, n, d;
	int			order, index;
	int			*val, d;
	bool		flag;
	COBJFace	face;
	
	for (len = 0; buf[len] != '\0'; len++);
	buf[len] = ' ';

	order = static_cast<int>(strlen (m_order));
	index = 0;

	val = new int [order];
	for (k = 0; k < order; k++)
		val[k] = 0;

	for (i = j = 0; i <= len; i++)
	{
		if (buf[i] == ' ')
		{
			if (j > 0)
			{
				for (d = 1; j > 0; j--)
				{
					val[index] += (tmp[j] - '0') * d;
					d *= 10;
				}
				index++;
			}

			for (k = 0, flag = true; k < order; k++)
			{
				if (val[k] == 0)
				{
					flag = false;
					break;
				}
			}

			if (flag)
			{
				for (k = 0; k < order; k++)
				{
					switch (m_order[k])
					{
					case 'v':
						face.m_vID.push_back (val[k] - 1);
						break;
					case 'n':
						face.m_vnID.push_back (val[k] - 1);
						break;
					case 't':
						face.m_vtID.push_back (val[k] - 1);
						break;
					}
				}

				index = 0;
				for (k = 0; k < order; k++)
					val[k] = 0;
			}
		}
		else if (buf[i] == '/')
		{
			if (j > 0)
			{
				for (d = 1; j > 0; j --)
				{
					val[index] += (tmp[j] - '0') * d;
					d *= 10;
				}
				index++;
			}
		}
		else if ('0' <= buf[i] && buf[i] <= '9')
		{
			j++;
			tmp[j] = buf[i];
		}
		else
		{
			m_iErrorCode = OBJERR_STRUCT;
			break;
		}
	}

	face.mMaterialName = mat;

	m_f.push_back (face);

	delete [] val;
}

unsigned int COBJModel::IsError ()
{
	return m_iErrorCode;
}

void COBJModel::drawEntity ()
{	
	deque<COBJFace>::iterator		i;
	deque<unsigned int>::iterator	j;

	for (i = m_f.begin (); i != m_f.end (); i++)
	{
		switch ((*i).m_vID.size ())
		{
		case 3:
			glBegin (GL_TRIANGLES);
			break;
		}

		for (j = (*i).m_vID.begin (); j != (*i).m_vID.end (); j++)
			glVertex3f (m_v[(*j)].x, m_v[(*j)].y, m_v[(*j)].z);

		glEnd ();
	}
}



/*
void COBJModel::ConsolePrint ()
{
	unsigned int i, j;

	// print vertices
	for (i = 0; i < m_iNumVertex; i++)
		printf("v\t%f\t%f\t%f\n", m_dqVertices[i].x, m_dqVertices[i].y, m_dqVertices[i].z);

	// print normals
	for (i = 0; i < m_iNumNormal; i++)
		printf("vn\t%f\t%f\t%f\n", m_dqNormals[i].x, m_dqNormals[i].y, m_dqNormals[i].z);

	// print faces
	for (i = 0; i < m_iNumFace; i++)
	{
		printf("f\t");
		for (j = 0; j < m_dqFaces[i].num; j++)
			printf("%d//%d\t", m_dqFaces[i].cs[j].v, m_dqFaces[i].cs[j].n);
		printf("\n");
	}
}

inline float COBJModel::Dot (stVertex a, stVertex b)
{
	return a.x * b.x + a.y * b.y + a.z * b.z;
}
*/
